#define keyLen 8
class A5Cripto{
char *orStr,*crStr;
typedef struct {unsigned long r1,r2,r3; } a5_ctx;
a5_ctx c;
static int threshold(unsigned int r1, unsigned int r2, unsigned int r3);
unsigned long clock_r1(int ctl, unsigned long r1);
unsigned long clock_r2(int ctl, unsigned long r2);
unsigned long clock_r3(int ctl,unsigned long r3);
int keystream(unsigned char *key, unsigned long frame, unsigned char *alice, unsigned char *bob);
void a5_key(a5_ctx *c, char *k);
int a5_step(a5_ctx *c);
void a5_encrypt(a5_ctx *c, char *data, int len);
void a5_decrypt(a5_ctx *c, char *data, int len);
int len;
unsigned char key[keyLen];
void move(char*,char*);
public:
A5Cripto::A5Cripto(){
orStr=NULL;
crStr=NULL;
}
A5Cripto::~A5Cripto(){
if(orStr)delete orStr;
if(crStr)delete crStr;
}
int getLenStr(){
return len;
}
const char* getOrStr(){
return orStr;
}
const char* getCrStr(){
return crStr;
}
bool setKey(char* _key);
char* SetOrigStr(char*,int);
char* SetCriptStr(char*,int);
void CriptStr(char* _key);
void decriptStr(char* _key);
AnsiString getAnsiData();
bool setAnsiData(AnsiString data);
};
//-----------------------------------------------------------------------
AnsiString A5Cripto::getAnsiData()
{
AnsiString str="",ch;
for(int i=0;i<len;i++){
ch=IntToStr(((char)crStr[i])+127);
while(ch.Length()<3)ch="0"+ch;
str+=ch;
}
return str;
}
//-----------------------------------------------------------------------
bool A5Cripto::setAnsiData(AnsiString data)
{
if(crStr)
delete crStr;
len=data.Length()/3;
crStr=new char[len+1];
AnsiString ch;
for(int i=0;i<len;i++){
ch=data.SubString(3*i+1,3);
crStr[i]=(char)(StrToInt(ch)-127);
ch="";
}
return true;
}
//-----------------------------------------------------------------------
void A5Cripto::move(char* from,char* to)
{
for(int i=0;i<len;i++){
to[i]=from[i];
}
to[len]='\0';
}
bool A5Cripto::setKey(char* _key){
if(strlen(_key)<keyLen)
return false;
for(int i=0;i<keyLen;i++){
key[i]=_key[i];
}
return true;
}
//-----------------------------------------------------------------------
char* A5Cripto::SetOrigStr(char* str,int _len){
if(orStr)
delete orStr;
len=_len;
orStr=new char[len+1];
move(str,orStr);
return orStr;
}
//-----------------------------------------------------------------------
char* A5Cripto::SetCriptStr(char* str,int _len){
if(crStr)
delete crStr;
len=_len;
crStr=new char[len+1];
move(str,crStr);
return crStr;
}
//-----------------------------------------------------------------------
void A5Cripto::CriptStr(char* _key)
{
setKey(_key);
char* tmp=new char[len+1];
move(orStr,tmp);
a5_key(&c,key);
a5_encrypt(&c,tmp,len);
SetCriptStr(tmp,len);
delete tmp;
}
//-----------------------------------------------------------------------
void A5Cripto::decriptStr(char* _key)
{
setKey(_key);
char* tmp=new char[len+1];
move(crStr,tmp);
a5_key(&c,key);
a5_decrypt(&c,tmp,1);
a5_decrypt(&c,tmp+1,len-1);
SetOrigStr(tmp,len);
delete tmp;
}
//-----------------------------------------------------------------------
int A5Cripto::threshold(unsigned int r1, unsigned int r2, unsigned int r3)
{
int total;
total = (((r1 >> 9) & 0x1) == 1)
+ (((r2 >> 11) & 0x1) == 1)
+ (((r3 >> 11) & 0x1) == 1) ;
if (total > 1)
return (0) ;
else
return (1) ;
}
//-----------------------------------------------------------------------
unsigned long A5Cripto::clock_r1(int ctl, unsigned long r1)
{
unsigned long feedback;
ctl ^= ( (r1 >> 9) & 0x1);
if (ctl)
{
feedback = (r1 >> 18) ^ (r1 >> 17) ^ (r1 >> 16) ^ (r1 >> 13);
r1 = (r1 << 1) & 0x7ffff;
if (feedback & 0x01)
r1 ^= 0x01;
}
return (r1);
}
//-----------------------------------------------------------------------
unsigned long A5Cripto::clock_r2(int ctl, unsigned long r2)
{
unsigned long feedback;
ctl ^= ( (r2 >> 11) & 0x1);
if (ctl)
{
feedback = (r2 >> 21) ^ (r2 >> 20) ^ (r2 >> 16) ^ (r2 >> 12);
r2 = (r2 << 1) & 0x3fffff;
if (feedback & 0x01)
r2 ^= 0x01;
}
return (r2);
}
//-----------------------------------------------------------------------
unsigned long A5Cripto::clock_r3(int ctl,unsigned long r3)
{
unsigned long feedback;
ctl ^= ( (r3 >> 11) & 0x1);
if (ctl)
{
feedback = (r3 >> 22) ^ (r3 >> 21) ^ (r3 >> 18) ^ (r3 >> 17);
r3 = (r3 << 1) & 0x7fffff;
if (feedback & 0x01)
r3 ^= 0x01;
}
return (r3);
}
//-----------------------------------------------------------------------
int A5Cripto::keystream(
unsigned char *key, /* 64 bit session key */
unsigned long frame, /* 22 bit frame sequence number */
unsigned char *alice, /* 114 bit Alice to Bob key stream */
unsigned char *bob) /* 114 bit Bob to Alice key stream */
{
unsigned long r1; /* 19 bit shift register */
unsigned long r2; /* 22 bit shift register */
/* 23 bit shift register */
unsigned long r3; int i;
int clock_ctl;
unsigned char *ptr;
unsigned char byte;
unsigned int bits;
unsigned int bit;
/* counter for loops
/* xored with clock enable on each shift register */
/* current position in keystream */
/* byte of keystream being assembled */
/* number of bits of keystream in byte */
/* bit output from keystream generator */
/* Initialise shift registers from session key */
r1 = (key[0] | (key[1] << 8) | (key[2] << 16) ) & 0x7ffff;
r2 = ((key[2] >> 3) | (key[3] << 5) | (key[4] << 13) | (key[5] << 21)) & 0x3fffff;
r3 = ((key[5] >> 1) | (key[6] << 7) | (key[7] << 15) ) & 0x7fffff;
Merge frame sequence number into shift register state,
// by xor'ing it * into the feedback path
for (i=0;i<22;i++) {
clock_ctl = threshold(r1, r2,r2);
r1 = clock_r1(clock_ctl,r1);
r2 = clock_r2(clock_ctl,r2);
r3 = clock_r3(clock_ctl, r3);
if (frame & 1) {
r1 ^= 1;
r2 ^= 1;
r3 ^= 1;
}
frame = frame >> 1;
}
// Run shift registers for 100 clock ticks to allow frame number to * be diffused
// into all the bits of the shift registers
for (i=0;i<100;i++) {
clock_ctl = threshold(r1, r2, r2);
r1 = clock_r1(clock_ctl, r1);
r2 = clock_r2(clock_ctl, r2);
r3 = clock_r3(clock_ctl, r3);
}
/* Produce 114 bits of Alice->Bob key stream */
ptr = alice;
bits = 0;
byte = 0;
for (i=0;i<114;i++)
{
clock_ctl = threshold(r1, r2 , r2);
r1 = clock_r1(clock_ctl, r1);
r2 = clock_r2(clock_ctl, r2);
r3 = clock_r3(clock_ctl, r3);
bit = ( (r1 >> 18) ^ (r2 >> 21) ^ (r3 >> 22)) & 0x01;
byte = (byte << 1) | bit;
bits++;
if (bits == 8) {
*ptr = byte;
ptr++;
bits = 0;
byte = 0;
}
}
if (bits)
*ptr = byte;
/* Run shift registers for another 100 bits to hide relationship between
* Alice->Bob key stream and Bob->Alice key stream.
*/
for (i=0;i<100;i++)
{
clock_ctl = threshold(r1, r2 ,r2);
r1 = clock_r1(clock_ctl, r1) ;
r2 = clock_r2(clock_ctl, r2) ;
r3 = clock_r3(clock_ctl, r3);
}
/* Produce 114 bits of Bob->Alice key stream */
ptr = bob;
bits = 0;
byte = 0;
for (i=0;i<114;i++)
{
clock_ctl = threshold(r1, r2 , r2);
r1 = clock_r1(clock_ctl, r1);
r2 = clock_r2(clock_ctl, r2);
r3 = clock_r3(clock_ctl, r3);
bit = ( (r1 >> 18) ^ (r2 >> 21) ^ (r3 >> 22)) & 0x01;
byte = (byte << 1) | bit;
bits++;
if (bits == 8)
{
*ptr = byte;
ptr++;
bits = 0;
byte = 0;
}
}
if (bits)
*ptr = byte;
return (0);
}
//-----------------------------------------------------------------------
void A5Cripto::a5_key(a5_ctx *c, char *k)
{
c->r1 = k[0]<<11|k[1]<<3 | k[2]>>5;
c->r2 = k[2]<<17|k[3]<<9 | k[4]<<1 | k[5]>>7;
c->r3 = k[5]<<15|k[6]<<8 | k[7];
}
//-----------------------------------------------------------------------
int A5Cripto::a5_step(a5_ctx *c)
{
int control;
control = threshold(c->r1,c->r2,c->r3);
c->r1 = clock_r1(control,c->r1) ;/* 19 */
c->r2 = clock_r2(control,c->r2) ;/* 22 */
c->r3 = clock_r3(control,c->r3) ;/* 23 */
return( (c->r1^c->r2^c->r3) &1);
}
//-----------------------------------------------------------------------
void A5Cripto::a5_encrypt(a5_ctx *c, char *data, int len)
{
int i,j;
char t;
for(i=0;i<len;i++){
for(j=0;j<8;j++) t = t<<1| a5_step(c);
data[i]^=t;
}
}
//-----------------------------------------------------------------------
void A5Cripto::a5_decrypt(a5_ctx *c, char *data, int len){
a5_encrypt(c,data,len);
}
|